#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

// 定义常量
const int QUEUE_SIZE = 10;

// 定义环形队列结构体
struct RingBuffer {
    int data[QUEUE_SIZE];
    int head;
    int tail;
    int count;
    sem_t empty;
    sem_t full;
    sem_t mutex;
};

// 初始化环形队列
void initRingBuffer(RingBuffer *rb) {
    rb->head = 0;
    rb->tail = 0;
    rb->count = 0;
    sem_init(&rb->empty, 1, QUEUE_SIZE); // 初始化信号量 中间变量1代表在进程之间共享，为0 代表在线程中间共享
    sem_init(&rb->full, 1, 0);
    sem_init(&rb->mutex, 1, 1);
}

// 销毁环形队列
void destroyRingBuffer(RingBuffer *rb) {
    sem_destroy(&rb->empty);
    sem_destroy(&rb->full);
    sem_destroy(&rb->mutex);
}

// 入队操作
void produce(RingBuffer *rb) {
    sem_wait(&rb->empty); // 等待空位
    sem_wait(&rb->mutex); // 获取互斥锁

    rb->data[rb->tail] = rb->tail; // 假设生产的数据就是索引值
    rb->tail = (rb->tail + 1) % QUEUE_SIZE;
    rb->count++;
    if(rb->tail != 0)
    std::cout << "Produced: " << rb->data[(rb->tail)-1] << std::endl;
    else
    std::cout << "Produced: " << rb->data[9] << std::endl;

    sem_post(&rb->mutex); // 释放互斥锁
    sem_post(&rb->full); // 通知消费者有空位
}

// 出队操作
void consume(RingBuffer *rb) {
    sem_wait(&rb->full); // 等待产品
    sem_wait(&rb->mutex); // 获取互斥锁

    int value = rb->data[rb->head]; // 取出队首元素
    rb->head = (rb->head + 1) % QUEUE_SIZE;
    rb->count--;

    std::cout << "Consumed: " << value << std::endl;

    sem_post(&rb->mutex); // 释放互斥锁
    sem_post(&rb->empty); // 通知生产者有空间
}

// 生产者线程函数
void* producerThread(void *arg) {
    RingBuffer *rb = (RingBuffer*)arg;
    for (int i = 0; i < 100; ++i) {
        produce(rb);
        sleep(1); // 暂停1秒，以便观察输出
    }
    return nullptr;
}

// 消费者线程函数
void* consumerThread(void *arg) {
    RingBuffer *rb = (RingBuffer*)arg;
    for (int i = 0; i < 100; ++i) {
        consume(rb);
       sleep(1); // 暂停1秒，以便观察输出
    }
    return nullptr;
}

int main() {
    RingBuffer rb;
    initRingBuffer(&rb);

    pthread_t producer, consumer;
    pthread_create(&producer, nullptr, producerThread, &rb);
    pthread_create(&consumer, nullptr, consumerThread, &rb);

    pthread_join(producer, nullptr);
    pthread_join(consumer, nullptr);

    destroyRingBuffer(&rb);
    return 0;
}